<?php
	/**
	 * Inheritable database class that provides the functionality to check results of the inherited class.
	 * @author IMP
	 */

	abstract class Database implements Resource {
		private $connected = false, $prefix;
		private $_host, $_user, $_pass, $_database;
		
		public final function connect($host, $user, $pass){
			if($this->connected) throw new DatabaseException('The database is already connected.');
			$this->connected = $this->__connect($host, $user, $pass) ? true : false;
			
			if($this->connected){
				$this->_host = $host;
				$this->_user = $user;
				$this->_pass = $pass;
			}
			
			return $this->connected;
		}
		
		public final function isConnected(){
			return $this->connected;
		}
		
		public final function selectDatabase($database, $prefix = ''){
			if(!$this->connected) throw new DatabaseException('The database is not connected.');
			
			$this->prefix = $prefix;
			if($this->__selectDatabase($database)){
				$this->_database = $database;
				return true;
			}else return false;
		}
		
		public final function getPrefix(){
			return $this->prefix;
		}
		
		public final function query($string){
			if(!$this->connected) throw new DatabaseException('The database is not connected.');
			
			$result = $this->__query($string);
			if($result instanceof DatabaseQueryResult){
				return $result;
			}elseif($result instanceof DatabaseError){
				throw $result;
			}else{
				throw new DatabaseException('Wrong implementation of __query in class ' . get_class($this) . '.');
			}
		}
		
		public final function execute($string){
			if(!$this->connected) throw new DatabaseException('The database is not connected.');
			
			$result = $this->__execute($string);
			if($result instanceof DatabaseError){
				throw $result;
			}
		}
		
		public final function disconnect(){
			if(!$this->connected) throw new DatabaseException('The database is not connected.');
			
			$this->connected = $this->__disconnect() ? false : true;
			return !$this->connected;
		}
		
		public final function getInfo(){
			if(!$this->connected) throw new DatabaseException('The database is not connected.');
			
			$info = $this->__getInfo();
			if($info instanceof DatabaseInformation){
				return $info;
			}else{
				throw new DatabaseException('Wrong implementation of __getInfo in class ' . get_class($this) . '.');
			}
		}
		
		public final function escape($string){
			$result = $this->__escape($string);
			
			if(strlen($result) >= strlen($string)){
				return $result;
			}else{
				throw new DatabaseException('Wrong implementation of __escape in class ' . get_class($this) . '.');
			}
		}
		
		public function save(File $f){
			$f->write('<?php $dbdata = ' . var_export(array('class' => get_class($this), 'host' => $this->_host, 'user' => $this->_user, 'pass' => $this->_pass, 'database' => $this->_database, 'prefix' => $this->prefix), true) . '; ?>');
		}
		
		public static function formFilename($name){
			return $name . '.db.php';
		}
		
		public static function open(File $f){
			include $f;
			
			if(isset($dbdata)){
				$db = new $dbdata['class'];
				$db->connect($dbdata['host'], $dbdata['user'], $dbdata['pass']);
				$db->selectDatabase($dbdata['database'], $dbdata['prefix']);
				
				unset($dbdata);
				
				return $db;
			}
		}
		
		public static function getResourceInformation(DataDirectory $d, $name){
			$f = $d->getAbsolutePath(self::formFilename($name));
			
			if(File::exists($path2file)){
				include $f;
			}else{
				throw new FileNotFoundException($f);
			}
		}
		
		abstract protected function __connect($host, $user, $pass);
		abstract protected function __selectDatabase($database);
		abstract protected function __query($string);
		abstract protected function __execute($string);
		abstract protected function __getInfo();
		abstract protected function __escape($string);
		abstract protected function __disconnect();
	}
?>